#include <stdio.h>
#include <string.h>

// ============= 第四课：指针与数组的深入关系 =============
// 探索数组遍历、字符串处理、多维数组等

// 函数声明
void demonstrate_array_pointer_equivalence(void);
void demonstrate_string_pointers(void);
void demonstrate_array_of_pointers(void);
void demonstrate_2d_arrays(void);
void reverse_string(char *str);
int string_length(char *str);
void print_strings(char *strings[], int count);

int main(void) {
    printf("=== C语言指针学习 - 第四课：指针与数组的深入关系 ===\n\n");
    
    // 1. 数组和指针的等价性
    demonstrate_array_pointer_equivalence();
    
    // 2. 字符串和指针
    demonstrate_string_pointers();
    
    // 3. 指针数组
    demonstrate_array_of_pointers();
    
    // 4. 二维数组和指针
    demonstrate_2d_arrays();
    
    printf("=== 第四课总结 ===\n");
    printf("1. 数组名可以当作指针使用，但不能被重新赋值\n");
    printf("2. 字符串本质上是字符数组，可以用指针操作\n");
    printf("3. 指针数组存储多个指针，常用于字符串数组\n");
    printf("4. 多维数组可以用指针的指针来理解\n");
    printf("5. 指针运算在数组操作中非常有用\n");
    printf("6. 理解指针与数组的关系是掌握C语言的关键\n");
    
    return 0;
}

void demonstrate_array_pointer_equivalence(void) {
    printf("1. 数组和指针的等价性：\n");
    
    int arr[5] = {10, 20, 30, 40, 50};
    int *ptr = arr;  // 指针指向数组第一个元素
    
    printf("   数组: [10, 20, 30, 40, 50]\n");
    printf("   int *ptr = arr;\n\n");
    
    // 展示不同的访问方式
    printf("   四种等价的访问方式:\n");
    for (int i = 0; i < 5; i++) {
        printf("   索引%d: arr[%d]=%d, *(arr+%d)=%d, ptr[%d]=%d, *(ptr+%d)=%d\n", 
               i, i, arr[i], i, *(arr+i), i, ptr[i], i, *(ptr+i));
    }
    
    printf("\n   地址比较:\n");
    printf("   arr = %p\n", (void*)arr);
    printf("   &arr[0] = %p\n", (void*)&arr[0]);
    printf("   ptr = %p\n", (void*)ptr);
    printf("   结论: arr 和 &arr[0] 和 ptr 都指向同一个地址\n\n");
    
    // 展示指针可以修改，但数组名不能
    printf("   指针可以重新赋值，但数组名不能:\n");
    int another_arr[3] = {100, 200, 300};
    ptr = another_arr;  // 合法：指针可以重新赋值
    printf("   ptr = another_arr; // 现在ptr指向新数组\n");
    printf("   *ptr = %d\n", *ptr);
    // arr = another_arr;  // 错误：数组名不能被重新赋值
    printf("   // arr = another_arr; // 编译错误！\n\n");
}

void demonstrate_string_pointers(void) {
    printf("2. 字符串和指针：\n");
    
    // 不同的字符串声明方式
    char str1[] = "Hello";           // 字符数组
    char *str2 = "World";            // 指针指向字符串字面量
    char str3[20] = "Programming";   // 固定大小字符数组
    
    printf("   三种字符串声明方式:\n");
    printf("   char str1[] = \"Hello\";          // 字符数组\n");
    printf("   char *str2 = \"World\";           // 指针指向字符串字面量\n");
    printf("   char str3[20] = \"Programming\";  // 固定大小字符数组\n\n");
    
    printf("   字符串内容:\n");
    printf("   str1 = %s (长度: %d)\n", str1, string_length(str1));
    printf("   str2 = %s (长度: %d)\n", str2, string_length(str2));
    printf("   str3 = %s (长度: %d)\n", str3, string_length(str3));
    printf("\n");
    
    // 字符串操作
    printf("   字符串操作示例:\n");
    printf("   反转str3前: %s\n", str3);
    reverse_string(str3);
    printf("   反转str3后: %s\n", str3);
    printf("\n");
    
    // 字符指针遍历
    printf("   使用指针遍历字符串:\n");
    char *message = "C Programming";
    char *p = message;
    printf("   逐字符输出: ");
    while (*p != '\0') {
        printf("%c", *p);
        p++;
    }
    printf("\n\n");
}

void demonstrate_array_of_pointers(void) {
    printf("3. 指针数组（字符串数组）：\n");
    
    // 字符串数组（指针数组）
    char *languages[] = {
        "C",
        "C++",
        "Python",
        "Java",
        "JavaScript"
    };
    
    int count = sizeof(languages) / sizeof(languages[0]);
    
    printf("   编程语言数组:\n");
    printf("   char *languages[] = {\"C\", \"C++\", \"Python\", \"Java\", \"JavaScript\"};\n\n");
    
    printf("   使用数组下标访问:\n");
    for (int i = 0; i < count; i++) {
        printf("   languages[%d] = %s\n", i, languages[i]);
    }
    printf("\n");
    
    printf("   使用指针访问:\n");
    char **ptr = languages;  // 指向指针的指针
    for (int i = 0; i < count; i++) {
        printf("   *(ptr + %d) = %s\n", i, *(ptr + i));
    }
    printf("\n");
    
    // 调用函数处理字符串数组
    printf("   通过函数处理字符串数组:\n");
    print_strings(languages, count);
    printf("\n");
}

void demonstrate_2d_arrays(void) {
    printf("4. 二维数组和指针：\n");
    
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };
    
    printf("   3x4矩阵:\n");
    for (int i = 0; i < 3; i++) {
        printf("   [");
        for (int j = 0; j < 4; j++) {
            printf("%2d", matrix[i][j]);
            if (j < 3) printf(", ");
        }
        printf("]\n");
    }
    printf("\n");
    
    // 使用指针访问二维数组
    printf("   使用指针访问二维数组:\n");
    int *ptr = (int*)matrix;  // 将二维数组视为一维数组
    
    printf("   线性访问 (将2D数组视为1D):\n");
    for (int i = 0; i < 12; i++) {
        printf("   ptr[%d] = %d", i, ptr[i]);
        if ((i + 1) % 4 == 0) printf(" (行结束)");
        printf("\n");
    }
    printf("\n");
    
    // 行指针
    printf("   使用行指针访问:\n");
    for (int i = 0; i < 3; i++) {
        int *row_ptr = matrix[i];  // 指向第i行
        printf("   第%d行: ", i);
        for (int j = 0; j < 4; j++) {
            printf("%d ", *(row_ptr + j));
        }
        printf("\n");
    }
    printf("\n");
}

// 反转字符串
void reverse_string(char *str) {
    if (str == NULL) return;
    
    int len = string_length(str);
    char *start = str;
    char *end = str + len - 1;
    
    while (start < end) {
        char temp = *start;
        *start = *end;
        *end = temp;
        start++;
        end--;
    }
}

// 计算字符串长度
int string_length(char *str) {
    if (str == NULL) return 0;
    
    int length = 0;
    while (*str != '\0') {
        length++;
        str++;
    }
    return length;
}

// 打印字符串数组
void print_strings(char *strings[], int count) {
    printf("   字符串列表:\n");
    for (int i = 0; i < count; i++) {
        printf("   %d. %s (长度: %d)\n", i+1, strings[i], string_length(strings[i]));
    }
} 